package treenode

import (
	"bytes"
	"encoding/json"
	"github.com/gogf/gf/v2/util/gconv"
)

// BuildTree 生成树形结构数据-不用查找节点
// 参数解析
// data：构建树的原始二维数组数据
// nodeId：从指定节点构建树
// Example:
//
//	data := []interface{
//			{Id: 1, Pid: 0, Name: ``},
//			{Id: 2, Pid: 0, Name: ``},
//			{Id: 3, Pid: 0, Name: ``},
//			{Id: 4, Pid: 1, Name: ``},
//			{Id: 5, Pid: 1, Name: ``},
//			{Id: 6, Pid: 1, Name: ``},
//			{Id: 7, Pid: 2, Name: ``},
//			{Id: 8, Pid: 3, Name: ``},
//			{Id: 9, Pid: 4, Name: ``},
//			{Id: 10, Pid: 0, Name: ``},
//			{Id: 11, Pid: 9, Name: ``},
//			{Id: 12, Pid: 9, Name: ``},
//		}
//
// New().BuildTrr(data)
// Output：[{"children":[{"children":[{"children":[{"children":[],"id":11,"is_show":0,"menu_type":0,"name":"","path":"","pid":9},{"children":[],"id":12,"is_show":0,"menu_type":0,"name":"","path":"","pid":9}],"id":9,"is_show":0,"menu_type":0,"name":"","path":"","pid":4}],"id":4,"is_show":0,"menu_type":0,"name":"","path":"","pid":1},{"children":[],"id":5,"is_show":0,"menu_type":0,"name":"","path":"","pid":1},{"children":[],"id":6,"is_show":0,"menu_type":0,"name":"","path":"","pid":1}],"id":1,"is_show":0,"menu_type":0,"name":"","path":"","pid":0},{"children":[{"children":[],"id":7,"is_show":0,"menu_type":0,"name":"","path":"","pid":2}],"id":2,"is_show":0,"menu_type":0,"name":"","path":"","pid":0},{"children":[{"children":[],"id":8,"is_show":0,"menu_type":0,"name":"","path":"","pid":3}],"id":3,"is_show":0,"menu_type":0,"name":"","path":"","pid":0},{"children":[],"id":10,"is_show":0,"menu_type":0,"name":"","path":"","pid":0}] <nil>
func (n *sTreeNode) BuildTree(data interface{}, nodeId ...uint) ([]map[string]interface{}, error) {
	return n.BuildFindTreeNode(data, nil, nodeId...)
}

// BuildFindTreeNode 生成树形结构数据并查找树的节点
// 参数解析
// data：构建树的原始二维数组数据
// findNode：查找节点ID
// nodeId：从指定节点构建树
// Example:
//
//	data := []interface{
//				{Id: 1, Pid: 0, Name: ``},
//				{Id: 2, Pid: 0, Name: ``},
//				{Id: 3, Pid: 0, Name: ``},
//				{Id: 4, Pid: 1, Name: ``},
//				{Id: 5, Pid: 1, Name: ``},
//				{Id: 6, Pid: 1, Name: ``},
//				{Id: 7, Pid: 2, Name: ``},
//				{Id: 8, Pid: 3, Name: ``},
//				{Id: 9, Pid: 4, Name: ``},
//				{Id: 10, Pid: 0, Name: ``},
//				{Id: 11, Pid: 9, Name: ``},
//				{Id: 12, Pid: 9, Name: ``},
//			}
//
// New().BuildFindTreeNode(data, []uint{1, 5, 7, 8, 10})
// Output：[{"children":[{"children":[{"children":[{"children":[],"id":11,"is_show":0,"menu_type":0,"name":"","path":"","pid":9,"selected":0},{"children":[],"id":12,"is_show":0,"menu_type":0,"name":"","path":"","pid":9,"selected":0}],"id":9,"is_show":0,"menu_type":0,"name":"","path":"","pid":4,"selected":2}],"id":4,"is_show":0,"menu_type":0,"name":"","path":"","pid":1,"selected":2},{"children":[],"id":5,"is_show":0,"menu_type":0,"name":"","path":"","pid":1,"selected":1},{"children":[],"id":6,"is_show":0,"menu_type":0,"name":"","path":"","pid":1,"selected":1}],"id":1,"is_show":0,"menu_type":0,"name":"","path":"","pid":0,"selected":2},{"children":[{"children":[],"id":7,"is_show":0,"menu_type":0,"name":"","path":"","pid":2,"selected":0}],"id":2,"is_show":0,"menu_type":0,"name":"","path":"","pid":0,"selected":0},{"children":[{"children":[],"id":8,"is_show":0,"menu_type":0,"name":"","path":"","pid":3,"selected":0}],"id":3,"is_show":0,"menu_type":0,"name":"","path":"","pid":0,"selected":0},{"children":[],"id":10,"is_show":0,"menu_type":0,"name":"","path":"","pid":0,"selected":1}] <nil>
func (n *sTreeNode) BuildFindTreeNode(data interface{}, findNode []uint, nodeId ...uint) ([]map[string]interface{}, error) {
	// 初始化生成父级树
	nodeMaps, err := n.toParentNode(n.Maps(data))
	if err != nil {
		return nil, err
	}

	// 默认从根节点构建树
	pid := nodeRootPid
	if len(nodeId) > 0 {
		pid = nodeId[0] // 可自定义从指定节点构建树
	}

	// 迭代生成子级树
	nodes, _ := n.buildTreeHandler(nodeMaps, pid, n.MapUintBool(findNode))
	return nodes, nil
}

// Maps 数据类型转换为MAP列表
func (n *sTreeNode) Maps(node interface{}) []map[string]interface{} {
	buff, err := json.Marshal(node)
	if err != nil {
		return nil
	}

	// 格式化MAP
	var nodes []map[string]interface{}
	if err = json.NewDecoder(bytes.NewBuffer(buff)).Decode(&nodes); err != nil {
		return nil
	}
	return nodes
}

// MapUintBool 转换已经勾选中的ID为MAP
func (n *sTreeNode) MapUintBool(selectedId []uint) map[uint]bool {
	// 为nil不进行查找节点
	if selectedId == nil {
		return nil
	}

	// 数据为空-也继续查找数据
	selectMap := make(map[uint]bool, len(selectedId))
	if len(selectedId) == 0 {
		return selectMap
	}
	// 迭代为转换MAP
	for _, id := range selectedId {
		selectMap[id] = true
	}
	return selectMap
}

// buildTreeHandler 处理并生成树形结构数据
func (n *sTreeNode) buildTreeHandler(nodeMaps map[uint][]map[string]interface{}, pid uint, findNode map[uint]bool) ([]map[string]interface{}, int) {
	// 勾选子层级数量,计算子层级是否完成了全部勾选
	var count int

	// 取出当前节点的树层
	nodes, ok := nodeMaps[pid]
	if !ok {
		return []map[string]interface{}{}, count
	}

	// 迭代查找子级树
	for _, node := range nodes {
		id := gconv.Uint(node[n.idColumn])
		// 迭代子级
		children, countChildSelected := n.buildTreeHandler(nodeMaps, id, findNode)

		// 设置子树层级和选中规则
		node[n.childrenColumn] = children

		// 处理是否勾选数据
		count = n.nodeSelectedHandler(selectedNode{
			count:      countChildSelected,
			findNode:   findNode,
			countChild: len(children),
			id:         id,
		}, &node)
	}
	// 返回数据
	return nodes, count
}

// nodeSelectedHandler 查找节点是否勾选处理
func (n *sTreeNode) nodeSelectedHandler(item selectedNode, node *map[string]interface{}) int {
	if item.findNode == nil {
		return 0
	}

	var (
		selectedFlag bool
		selected     = selectedNot
	)
	// 当前层级（父级）是否已勾选中
	_, selectedFlag = item.findNode[item.id]

	if item.count == -1 || (item.countChild > 0 && item.countChild > item.count && selectedFlag) {
		// 若是子级返回-1，则父级为部分勾选，向上传递
		selected = selectedPartial
		if item.count >= 0 {
			item.count = -1 // 子级存在不完全勾选，则所有上级（父级、祖父级。。。）都设置未部分勾选，向上传递
		}
	} else if selectedFlag {
		// 子级勾选
		selected = selectedUp
		item.count += 1 // 累计此层勾选中数量
	}

	// 设置是否选择
	if node != nil {
		// 解引用指针创建Map传递指针的副本复值选中字段
		(*node)[n.selectedColumn] = selected
	}
	return item.count
}

// toParentNode 转换树形结构数据为父级ID集合二维数组
func (n *sTreeNode) toParentNode(nodes []map[string]interface{}) (map[uint][]map[string]interface{}, error) {
	nodeMaps := make(map[uint][]map[string]interface{})
	if len(nodes) == 0 {
		return nodeMaps, nil
	}

	// 迭代把二维数组转换为父级ID集合的二维数组
	for _, node := range nodes {
		// 字段检测
		if err := n.IsField(node); err != nil {
			return nil, err
		}
		pid := gconv.Uint(node[n.pidColumn])
		nodeMaps[pid] = append(nodeMaps[pid], node)
	}
	return nodeMaps, nil
}
